package com.dxb.test.sort;

/**
 * 基数排序
 * 基本思想：
 * 基数排序是在BinSort的基础上，通过基数的限制来减少空间的开销。
 * 基数排序(Radix Sort)是桶排序的扩展，它的基本思想是：将整数按位数切割成不同的数字，然后按每个位数分别比较。
 * 排序过程：将所有待比较数值（正整数）统一为同样的数位长度，数位较短的数前面补零。
 * 然后，从最低位开始，依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
 */
public class RadixSort extends BaseSort {
    private int radix = 10;

    public RadixSort(int[] array) {
        super(array);
    }

    @Override
    public void sort() {
        // 数组的第一维表示可能的余数0-radix，第二维表示array中的等于该余数的元素
        // 如：十进制123的个位为3，则bucket[3][] = {123}
        int[][] bucket = new int[radix][length];
        // 表示最大的数有多少位
        int distance = getDistance();
        // 控制键值排序依据在哪一位
        int round = 1;
        int temp = 1;
        while (round <= distance) {
            // 用来计数：数组counter[i]用来表示该位是i的数的个数，数据取模后，会有相同的值
            int[] counter = new int[radix];
            // 将array中元素分布填充到bucket中，并进行计数
            for (int i = 0; i < length; i++) {
                int which = (array[i] / temp) % radix;
                //取模数字，第counter[which]次出现
                bucket[which][counter[which]] = array[i];
                //出现一次加一次，方便下次出现赋值
                counter[which]++;
            }
            int index = 0;
            // 根据bucket中收集到的array中的元素，根据统计计数，在array中重新排列
            for (int i = 0; i < radix; i++) {
                if (counter[i] != 0) {
                    for (int j = 0; j < counter[i]; j++) {
                        array[index] = bucket[i][j];
                        index++;
                    }
                }
                counter[i] = 0;
            }
            round++;
            temp *= radix;
        }
    }

    private int getDistance() {
        int max = computeMax();
        int digits = 0;
        while (max != 0) {
            digits++;
            max = max / radix;
        }
        return digits;
    }

    private int computeMax() {
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        return max;
    }

    public static void main(String args[]) {
        int[] array = {99, 78, 26, 17, 82, 36, 9, 81, 22, 100, 30, 20, 17, 85};
        BaseSort qs = new RadixSort(array);
        qs.run();
    }
}
